package com.example.blog.config;

import com.auth0.jwt.JWT;
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.example.blog.annotation.RequiresPermission;
import com.example.blog.entity.UserInfo;
import com.example.blog.enums.Role;
import com.example.blog.exception.NewWifiLoginException;
import com.example.blog.service.UserInfoService;
import com.example.blog.util.RedisUtil;
import com.example.blog.util.UserTokenManager;
import com.example.blog.vo.RoleAndPermission;
import com.github.xiaoymin.knife4j.core.util.CollectionUtils;
import com.github.xiaoymin.knife4j.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.hibernate.service.spi.ServiceException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @ClassName: PermissionCheck
 * @Description:

 * @Date 2024/2/6
 * @Version 1.0
 */
@Slf4j
@Aspect
@Component
public class PermissionCheck {
    @Autowired
    private RedisUtil redisUtil;
    @Autowired
    private UserInfoService userInfoService;


    /***
     * @MethodName: permissionCheckPointCut
     * @description: 定义一个切点
     * @Author: LiuTao
     * @UpdateTime: 2023/6/20 19:34
     **/
    @Pointcut("@annotation(com.example.blog.annotation.RequiresPermission)")
    public void permissionCheckPointCut() {

    }

    /***
     * @MethodName: check
     * @description: 环绕通知
     * @Author: LiuTao
     * @Param: [pjp]
     * @UpdateTime: 2023/6/20 19:34
     * @Return: java.lang.Object
     * @Throw: Throwable
     **/
    @Around("permissionCheckPointCut()")
    public Object check(ProceedingJoinPoint pjp) throws Throwable {
        // 获取请求对象
        HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
        // 记录日志
        log.info("===============系统操作日志===============");
        Signature signature = pjp.getSignature();
        // 请求的类
        String className = pjp.getTarget().getClass().getName();
        String methodName = signature.getName();
        log.info("请求方式：{}", request.getMethod());
        log.info("请求ip：{}", request.getRemoteAddr());
        log.info("请求类方法：{}", signature);
        log.info("请求参数：{}", Arrays.toString(pjp.getArgs()));
        // 权限注解校验
        MethodSignature handlerMethod = (MethodSignature) signature;
        Method method = handlerMethod.getMethod();
        if (method.isAnnotationPresent(RequiresPermission.class)) {
            RequiresPermission auth = method.getAnnotation(RequiresPermission.class);
            String[] roles = auth.roles();
            String[] permissions1 = auth.permissions();

            String token = request.getHeader("cloud-Auth-Token");
            // 认证
            if (StrUtil.isBlank(token)) {
                throw new NewWifiLoginException( "请登录!!!",HttpStatus.UNAUTHORIZED.value());
            }
            String id;
            try {
                id = UserTokenManager.getUserId(token);
            } catch (JWTDecodeException jwtDecodeException) {
                throw new NewWifiLoginException("token验证失败，请重新登录",HttpStatus.UNAUTHORIZED.value());
            }
            List<RoleAndPermission> byId = userInfoService.getById(id);
            if (byId.size() == 0) {
                throw new NewWifiLoginException("无权限访问资源",HttpStatus.UNAUTHORIZED.value());
            }
            // 校验角色
            if (!CollectionUtils.isEmpty(roles)) {
                List<String> stringList = Arrays.asList(roles);
                List<String> stringList1 = new ArrayList<>();
                byId.forEach(roleAndPermission -> {
                    stringList1.add(roleAndPermission.getRoleId());
                });
                List<String> stringList2 = intersectList2(stringList1, stringList);
                if (stringList2.size() == 0 ) {
                    throw new NewWifiLoginException("当前角色权限不足",HttpStatus.UNAUTHORIZED.value());
                }
            }
        }
        return pjp.proceed();
    }
    public static List<String> intersectList2(List<String> list1, List<String> list2){
        Map<String, String> tempMap = list2.parallelStream().collect(Collectors.toMap(Function.identity(), Function.identity(), (oldData, newData) -> newData));
        return list1.parallelStream().filter(str->{
            return tempMap.containsKey(str);
        }).collect(Collectors.toList());
    }
}
